#include "StdAfx.h"
#include "LocalVertexFactory.h"

#include "SceneNode.h"
#include "MeshInstance.h"

#include "Shader.h"

using namespace RenderSystem;


void LocalVertexFactoryShaderParameters::Bind(const ShaderParameterMap& ParameterMap)
{
	m_LocalToWorldParameter.Bind(ParameterMap,TEXT("LocalToWorld"),TRUE); // optional as instanced meshes don't need it
	m_LocalToWorldRotDeterminantFlipParameter.Bind(ParameterMap,TEXT("LocalToWorldRotDeterminantFlip"),TRUE);
	m_WorldToLocalParameter.Bind(ParameterMap,TEXT("WorldToLocal"),TRUE);
}

void LocalVertexFactoryShaderParameters::Set(Shader* VertexShader,const VertexFactory* VertexFactory) const
{	
}

void LocalVertexFactoryShaderParameters::SetMesh(Shader* pVertexShader, const SubMeshInstance& rSubMeshInstance) const
{
	const VertexShader* pRawVertexShader = pVertexShader->GetVertexShader();

	MeshInstance* pMeshInstance = rSubMeshInstance.GetOwner();
	assert( pMeshInstance != NULL );
	SceneNode* pAttachedNode = pMeshInstance->GetAttachNode();
	assert( pAttachedNode != NULL );

	SetVertexShaderValue( pVertexShader->GetVertexShader(), m_LocalToWorldParameter, pAttachedNode->GetWorldTransformation() );

	/*
	if (LocalToWorldRotDeterminantFlipParameter.IsBound())
	{
		// Used to flip the normal direction if LocalToWorldRotDeterminant is negative.  
		// This prevents non-uniform negative scaling from making vectors transformed with CalcTangentToWorld pointing in the wrong quadrant.
		FLOAT LocalToWorldRotDeterminant = Mesh.LocalToWorld.RotDeterminant();
		SetVertexShaderValue(
			VertexShader->GetVertexShader(),
			LocalToWorldRotDeterminantFlipParameter,
			appFloatSelect(LocalToWorldRotDeterminant, 1, -1)
			);
	}
	*/

	//SetVertexShaderValue( pVertexShader->GetVertexShader(), m_WorldToLocalParameter, Mesh.WorldToLocal);
}

LocalVertexFactory::SetVertexShaderValue( ShaderType* pShaderType )
{

}

////////////////////////////////////////////////////////////LocalVertexFactory////////////////////////////////////////////////////////////
//////////////////////////////
/**
* Copy the data from another vertex factory
* @param Other - factory to copy from
*/
void LocalVertexFactory::Copy(const LocalVertexFactory& Other)
{
	ENQUEUE_UNIQUE_RENDER_COMMAND_TWOPARAMETER(
		LocalVertexFactoryCopyData,
		LocalVertexFactory*,VertexFactory,this,
		const DataType*,DataCopy,&Other.Data,
	{
		VertexFactory->Data = *DataCopy;
	});
	BeginUpdateResourceRHI(this);
}

/**
* Vertex factory interface for creating a corresponding decal vertex factory
* Copies the data from this existing vertex factory.
*
* @return new allocated decal vertex factory
*/
FDecalVertexFactoryBase* LocalVertexFactory::CreateDecalVertexFactory() const
{
	FLocalDecalVertexFactory* DecalFactory = new FLocalDecalVertexFactory();
	DecalFactory->Copy(*this);
	return DecalFactory;
}

void LocalVertexFactory::InitRHI()
{
	// If the vertex buffer containing position is not the same vertex buffer containing the rest of the data,
	// then initialize PositionStream and PositionDeclaration.
	if(Data.PositionComponent.VertexBuffer != Data.TangentBasisComponents[0].VertexBuffer)
	{
		VertexDeclarationElementList PositionOnlyStreamElements;
		PositionOnlyStreamElements.AddItem(AccessPositionStreamComponent(Data.PositionComponent,VEU_Position));
		InitPositionDeclaration(PositionOnlyStreamElements);
	}

	VertexDeclarationElementList Elements;
	if(Data.PositionComponent.VertexBuffer != NULL)
	{
		Elements.AddItem(AccessStreamComponent(Data.PositionComponent,VEU_Position));
	}

	// only tangent,normal are used by the stream. the binormal is derived in the shader
	EVertexElementUsage TangentBasisUsages[2] = { VEU_Tangent, VEU_Normal };
	for(INT AxisIndex = 0;AxisIndex < 2;AxisIndex++)
	{
		if(Data.TangentBasisComponents[AxisIndex].VertexBuffer != NULL)
		{
			Elements.AddItem(AccessStreamComponent(Data.TangentBasisComponents[AxisIndex],TangentBasisUsages[AxisIndex]));
		}
	}

	if(Data.ColorComponent.VertexBuffer)
	{
		Elements.AddItem(AccessStreamComponent(Data.ColorComponent,VEU_Color,1));
	}
	else
	{
		//If the mesh has no color component, set the null color buffer on a new stream with a stride of 0.
		//This wastes 4 bytes of bandwidth per vertex, but prevents having to compile out twice the number of vertex factories.
		FVertexStreamComponent NullColorComponent(&GNullColorVertexBuffer, 0, 0, VET_Color);
		Elements.AddItem(AccessStreamComponent(NullColorComponent,VEU_Color,1));
	}

	if(Data.TextureCoordinates.Num())
	{
		for(UINT CoordinateIndex = 0;CoordinateIndex < Data.TextureCoordinates.Num();CoordinateIndex++)
		{
			Elements.AddItem(AccessStreamComponent(
				Data.TextureCoordinates(CoordinateIndex),
				VEU_TextureCoordinate,
				CoordinateIndex
				));
		}

		for(UINT CoordinateIndex = Data.TextureCoordinates.Num();CoordinateIndex < MAX_TEXCOORDS;CoordinateIndex++)
		{
			Elements.AddItem(AccessStreamComponent(
				Data.TextureCoordinates(Data.TextureCoordinates.Num() - 1),
				VEU_TextureCoordinate,
				CoordinateIndex
				));
		}
	}

	if(Data.ShadowMapCoordinateComponent.VertexBuffer)
	{
		Elements.AddItem(AccessStreamComponent(Data.ShadowMapCoordinateComponent,VEU_Color));
	}
	else if(Data.TextureCoordinates.Num())
	{
		Elements.AddItem(AccessStreamComponent(Data.TextureCoordinates(0),VEU_Color));
	}

	InitDeclaration(Elements,Data);
}

IMPLEMENT_VERTEX_FACTORY_TYPE(LocalVertexFactory,LocalVertexFactoryShaderParameters,"LocalVertexFactory",TRUE,TRUE,TRUE);
IMPLEMENT_VERTEX_FACTORY_TYPE(LocalShadowVertexFactory,LocalVertexFactoryShaderParameters,"LocalVertexFactory",FALSE,FALSE,TRUE);
